home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Objects / bufferobject.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-10  |  11.5 KB  |  612 lines

  1. /* Buffer object implementation */
  2.  
  3. #include "Python.h"
  4.  
  5.  
  6. typedef struct {
  7.     PyObject_HEAD
  8.     PyObject *b_base;
  9.     void *b_ptr;
  10.     int b_size;
  11.     int b_readonly;
  12. #ifdef CACHE_HASH
  13.     long b_hash;
  14. #endif
  15. } PyBufferObject;
  16.  
  17. #include "protos/bufferobject.h"
  18.  
  19.  
  20. static PyObject *
  21. _PyBuffer_FromMemory(base, ptr, size, readonly)
  22.     PyObject *base;
  23.     void *ptr;
  24.     int size;
  25.     int readonly;
  26. {
  27.     PyBufferObject * b;
  28.  
  29.     if ( size < 0 ) {
  30.         PyErr_SetString(PyExc_ValueError,
  31.                 "size must be zero or positive");
  32.         return NULL;
  33.     }
  34.  
  35.     b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
  36.     if ( b == NULL )
  37.         return NULL;
  38.  
  39.     Py_XINCREF(base);
  40.     b->b_base = base;
  41.     b->b_ptr = ptr;
  42.     b->b_size = size;
  43.     b->b_readonly = readonly;
  44. #ifdef CACHE_HASH
  45.     b->b_hash = -1;
  46. #endif
  47.  
  48.     return (PyObject *) b;
  49. }
  50.  
  51. static PyObject *
  52. _PyBuffer_FromObject(base, offset, size, proc, readonly)
  53.     PyObject *base;
  54.     int offset;
  55.     int size;
  56.     getreadbufferproc proc;
  57.     int readonly;
  58. {
  59.     PyBufferProcs *pb = base->ob_type->tp_as_buffer;
  60.     void *p;
  61.     int count;
  62.  
  63.     if ( offset < 0 ) {
  64.         PyErr_SetString(PyExc_ValueError,
  65.                 "offset must be zero or positive");
  66.         return NULL;
  67.     }
  68.  
  69.     if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
  70.     {
  71.         PyErr_SetString(PyExc_TypeError,
  72.                 "single-segment buffer object expected");
  73.         return NULL;
  74.     }
  75.     if ( (count = (*proc)(base, 0, &p)) < 0 )
  76.         return NULL;
  77.  
  78.     /* apply constraints to the start/end */
  79.     if ( size == Py_END_OF_BUFFER || size < 0 )
  80.         size = count;
  81.     if ( offset > count )
  82.         offset = count;
  83.     if ( offset + size > count )
  84.         size = count - offset;
  85.  
  86.     /* if the base object is another buffer, then "deref" it */
  87.     if ( PyBuffer_Check(base) )
  88.         base = ((PyBufferObject *)base)->b_base;
  89.  
  90.     return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
  91. }
  92.  
  93.  
  94. PyObject *
  95. PyBuffer_FromObject(base, offset, size)
  96.     PyObject *base;
  97.     int offset;
  98.     int size;
  99. {
  100.     PyBufferProcs *pb = base->ob_type->tp_as_buffer;
  101.  
  102.     if ( pb == NULL ||
  103.          pb->bf_getreadbuffer == NULL ||
  104.          pb->bf_getsegcount == NULL )
  105.     {
  106.         PyErr_SetString(PyExc_TypeError, "buffer object expected");
  107.         return NULL;
  108.     }
  109.  
  110.     return _PyBuffer_FromObject(base, offset, size,
  111.                     pb->bf_getreadbuffer, 1);
  112. }
  113.  
  114. PyObject *
  115. PyBuffer_FromReadWriteObject(base, offset, size)
  116.     PyObject *base;
  117.     int offset;
  118.     int size;
  119. {
  120.     PyBufferProcs *pb = base->ob_type->tp_as_buffer;
  121.  
  122.     if ( pb == NULL ||
  123.          pb->bf_getwritebuffer == NULL ||
  124.          pb->bf_getsegcount == NULL )
  125.     {
  126.         PyErr_SetString(PyExc_TypeError, "buffer object expected");
  127.         return NULL;
  128.     }
  129.  
  130.     return _PyBuffer_FromObject(base, offset, size,
  131.                     (getreadbufferproc)pb->bf_getwritebuffer,
  132.                     0);
  133. }
  134.  
  135. PyObject *
  136. PyBuffer_FromMemory(ptr, size)
  137.     void *ptr;
  138.     int size;
  139. {
  140.     return _PyBuffer_FromMemory(NULL, ptr, size, 1);
  141. }
  142.  
  143. PyObject *
  144. PyBuffer_FromReadWriteMemory(ptr, size)
  145.     void *ptr;
  146.     int size;
  147. {
  148.     return _PyBuffer_FromMemory(NULL, ptr, size, 0);
  149. }
  150.  
  151. PyObject *
  152. PyBuffer_New(size)
  153.     int size;
  154. {
  155.     PyBufferObject * b;
  156.  
  157.     if (size < 0) {
  158.         PyErr_SetString(PyExc_ValueError,
  159.                 "size must be zero or positive");
  160.         return NULL;
  161.     }
  162.     /* PyObject_New is inlined */
  163.     b = (PyBufferObject *) PyObject_MALLOC(sizeof(*b) + size);
  164.     if ( b == NULL )
  165.         return PyErr_NoMemory();
  166.     PyObject_INIT((PyObject *)b, &PyBuffer_Type);
  167.  
  168.     b->b_base = NULL;
  169.     b->b_ptr = (void *)(b + 1);
  170.     b->b_size = size;
  171.     b->b_readonly = 0;
  172. #ifdef CACHE_HASH
  173.     b->b_hash = -1;
  174. #endif
  175.  
  176.     return (PyObject *) b;
  177. }
  178.  
  179. /* Methods */
  180.  
  181. static void
  182. buffer_dealloc(self)
  183.     PyBufferObject *self;
  184. {
  185.     Py_XDECREF(self->b_base);
  186.     PyObject_DEL(self);
  187. }
  188.  
  189. static int
  190. buffer_compare(self, other)
  191.     PyBufferObject *self;
  192.     PyBufferObject *other;
  193. {
  194.     int len_self = self->b_size;
  195.     int len_other = other->b_size;
  196.     int min_len = (len_self < len_other) ? len_self : len_other;
  197.     int cmp;
  198.     if (min_len > 0) {
  199.         cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
  200.         if (cmp != 0)
  201.             return cmp;
  202.     }
  203.     return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
  204. }
  205.  
  206. static PyObject *
  207. buffer_repr(self)
  208.     PyBufferObject *self;
  209. {
  210.     char buf[300];
  211.     char *status = self->b_readonly ? "read-only" : "read-write";
  212.  
  213.     if ( self->b_base == NULL )
  214.     {
  215.         sprintf(buf, "<%s buffer ptr %lx, size %d at %lx>",
  216.             status,
  217.             (long)self->b_ptr,
  218.             self->b_size,
  219.             (long)self);
  220.     }
  221.     else
  222.     {
  223.         sprintf(buf, "<%s buffer for %lx, ptr %lx, size %d at %lx>",
  224.             status,
  225.             (long)self->b_base,
  226.             (long)self->b_ptr,
  227.             self->b_size,
  228.             (long)self);
  229.     }
  230.  
  231.     return PyString_FromString(buf);
  232. }
  233.  
  234. static long
  235. buffer_hash(self)
  236.     PyBufferObject *self;
  237. {
  238.     register int len;
  239.     register unsigned char *p;
  240.     register long x;
  241.  
  242. #ifdef CACHE_HASH
  243.     if ( self->b_hash != -1 )
  244.         return self->b_hash;
  245. #endif
  246.  
  247.     if ( !self->b_readonly )
  248.     {
  249.         /* ### use different wording, since this is conditional? */
  250.         PyErr_SetString(PyExc_TypeError, "unhashable type");
  251.         return -1;
  252.     }
  253.  
  254.     len = self->b_size;
  255.     p = (unsigned char *) self->b_ptr;
  256.     x = *p << 7;
  257.     while (--len >= 0)
  258.         x = (1000003*x) ^ *p++;
  259.     x ^= self->b_size;
  260.     if (x == -1)
  261.         x = -2;
  262. #ifdef CACHE_HASH
  263.     self->b_hash = x;
  264. #endif
  265.     return x;
  266. }
  267.  
  268. static PyObject *
  269. buffer_str(self)
  270.     PyBufferObject *self;
  271. {
  272.     return PyString_FromStringAndSize(self->b_ptr, self->b_size);
  273. }
  274.  
  275. /* Sequence methods */
  276.  
  277. static int
  278. buffer_length(self)
  279.     PyBufferObject *self;
  280. {
  281.     return self->b_size;
  282. }
  283.  
  284. static PyObject *
  285. buffer_concat(self, other)
  286.     PyBufferObject *self;
  287.     PyObject *other;
  288. {
  289.     PyBufferProcs *pb = other->ob_type->tp_as_buffer;
  290.     char *p1;
  291.     void *p2;
  292.     PyObject *ob;
  293.     int count;
  294.  
  295.     if ( pb == NULL ||
  296.          pb->bf_getreadbuffer == NULL ||
  297.          pb->bf_getsegcount == NULL )
  298.     {
  299.         PyErr_BadArgument();
  300.         return NULL;
  301.     }
  302.     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
  303.     {
  304.         /* ### use a different exception type/message? */
  305.         PyErr_SetString(PyExc_TypeError,
  306.                 "single-segment buffer object expected");
  307.         return NULL;
  308.     }
  309.  
  310.     /* optimize special case */
  311.     if ( self->b_size == 0 )
  312.     {
  313.         Py_INCREF(other);
  314.         return other;
  315.     }
  316.  
  317.     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
  318.         return NULL;
  319.  
  320.     /* optimize special case */
  321.     if ( count == 0 )
  322.     {
  323.         Py_INCREF(self);
  324.         return (PyObject *)self;
  325.     }
  326.  
  327.     ob = PyString_FromStringAndSize(NULL, self->b_size + count);
  328.     p1 = PyString_AS_STRING(ob);
  329.     memcpy(p1, self->b_ptr, self->b_size);
  330.     memcpy(p1 + self->b_size, p2, count);
  331.  
  332.     /* there is an extra byte in the string object, so this is safe */
  333.     p1[self->b_size + count] = '\0';
  334.  
  335.     return ob;
  336. }
  337.  
  338. static PyObject *
  339. buffer_repeat(self, count)
  340.     PyBufferObject *self;
  341.     int count;
  342. {
  343.     PyObject *ob;
  344.     register char *p;
  345.     void *ptr = self->b_ptr;
  346.     int size = self->b_size;
  347.  
  348.     if ( count < 0 )
  349.         count = 0;
  350.     ob = PyString_FromStringAndSize(NULL, size * count);
  351.     if ( ob == NULL )
  352.         return NULL;
  353.  
  354.     p = PyString_AS_STRING(ob);
  355.     while ( count-- )
  356.     {
  357.         memcpy(p, ptr, size);
  358.         p += size;
  359.     }
  360.  
  361.     /* there is an extra byte in the string object, so this is safe */
  362.     *p = '\0';
  363.  
  364.     return ob;
  365. }
  366.  
  367. static PyObject *
  368. buffer_item(self, idx)
  369.     PyBufferObject *self;
  370.     int idx;
  371. {
  372.     if ( idx < 0 || idx >= self->b_size )
  373.     {
  374.         PyErr_SetString(PyExc_IndexError, "buffer index out of range");
  375.         return NULL;
  376.     }
  377.     return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
  378. }
  379.  
  380. static PyObject *
  381. buffer_slice(self, left, right)
  382.     PyBufferObject *self;
  383.     int left;
  384.     int right;
  385. {
  386.     if ( left < 0 )
  387.         left = 0;
  388.     if ( right < 0 )
  389.         right = 0;
  390.     if ( right > self->b_size )
  391.         right = self->b_size;
  392.     if ( left == 0 && right == self->b_size )
  393.     {
  394.         /* same as self */
  395.         Py_INCREF(self);
  396.         return (PyObject *)self;
  397.     }
  398.     if ( right < left )
  399.         right = left;
  400.     return PyString_FromStringAndSize((char *)self->b_ptr + left,
  401.                       right - left);
  402. }
  403.  
  404. static int
  405. buffer_ass_item(self, idx, other)
  406.     PyBufferObject *self;
  407.     int idx;
  408.     PyObject *other;
  409. {
  410.     PyBufferProcs *pb;
  411.     void *p;
  412.     int count;
  413.  
  414.     if ( self->b_readonly ) {
  415.         PyErr_SetString(PyExc_TypeError,
  416.                 "buffer is read-only");
  417.         return -1;
  418.     }
  419.  
  420.     if (idx < 0 || idx >= self->b_size) {
  421.         PyErr_SetString(PyExc_IndexError,
  422.                 "buffer assignment index out of range");
  423.         return -1;
  424.     }
  425.  
  426.     pb = other ? other->ob_type->tp_as_buffer : NULL;
  427.     if ( pb == NULL ||
  428.          pb->bf_getreadbuffer == NULL ||
  429.          pb->bf_getsegcount == NULL )
  430.     {
  431.         PyErr_BadArgument();
  432.         return -1;
  433.     }
  434.     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
  435.     {
  436.         /* ### use a different exception type/message? */
  437.         PyErr_SetString(PyExc_TypeError,
  438.                 "single-segment buffer object expected");
  439.         return -1;
  440.     }
  441.  
  442.     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
  443.         return -1;
  444.     if ( count != 1 ) {
  445.         PyErr_SetString(PyExc_TypeError,
  446.                 "right operand must be a single byte");
  447.         return -1;
  448.     }
  449.  
  450.     ((char *)self->b_ptr)[idx] = *(char *)p;
  451.     return 0;
  452. }
  453.  
  454. static int
  455. buffer_ass_slice(self, left, right, other)
  456.     PyBufferObject *self;
  457.     int left;
  458.     int right;
  459.     PyObject *other;
  460. {
  461.     PyBufferProcs *pb;
  462.     void *p;
  463.     int slice_len;
  464.     int count;
  465.  
  466.     if ( self->b_readonly ) {
  467.         PyErr_SetString(PyExc_TypeError,
  468.                 "buffer is read-only");
  469.         return -1;
  470.     }
  471.  
  472.     pb = other ? other->ob_type->tp_as_buffer : NULL;
  473.     if ( pb == NULL ||
  474.          pb->bf_getreadbuffer == NULL ||
  475.          pb->bf_getsegcount == NULL )
  476.     {
  477.         PyErr_BadArgument();
  478.         return -1;
  479.     }
  480.     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
  481.     {
  482.         /* ### use a different exception type/message? */
  483.         PyErr_SetString(PyExc_TypeError,
  484.                 "single-segment buffer object expected");
  485.         return -1;
  486.     }
  487.     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
  488.         return -1;
  489.  
  490.     if ( left < 0 )
  491.         left = 0;
  492.     else if ( left > self->b_size )
  493.         left = self->b_size;
  494.     if ( right < left )
  495.         right = left;
  496.     else if ( right > self->b_size )
  497.         right = self->b_size;
  498.     slice_len = right - left;
  499.  
  500.     if ( count != slice_len ) {
  501.         PyErr_SetString(
  502.             PyExc_TypeError,
  503.             "right operand length must match slice length");
  504.         return -1;
  505.     }
  506.  
  507.     if ( slice_len )
  508.         memcpy((char *)self->b_ptr + left, p, slice_len);
  509.  
  510.     return 0;
  511. }
  512.  
  513. /* Buffer methods */
  514.  
  515. static int
  516. buffer_getreadbuf(self, idx, pp)
  517.     PyBufferObject *self;
  518.     int idx;
  519.     void ** pp;
  520. {
  521.     if ( idx != 0 ) {
  522.         PyErr_SetString(PyExc_SystemError,
  523.                 "accessing non-existent buffer segment");
  524.         return -1;
  525.     }
  526.     *pp = self->b_ptr;
  527.     return self->b_size;
  528. }
  529.  
  530. static int
  531. buffer_getwritebuf(self, idx, pp)
  532.     PyBufferObject *self;
  533.     int idx;
  534.     void ** pp;
  535. {
  536.     if ( self->b_readonly )
  537.     {
  538.         PyErr_SetString(PyExc_TypeError, "buffer is read-only");
  539.         return -1;
  540.     }
  541.     return buffer_getreadbuf(self, idx, pp);
  542. }
  543.  
  544. static int
  545. buffer_getsegcount(self, lenp)
  546.     PyBufferObject *self;
  547.     int *lenp;
  548. {
  549.     if ( lenp )
  550.         *lenp = self->b_size;
  551.     return 1;
  552. }
  553.  
  554. static int
  555. buffer_getcharbuf(self, idx, pp)
  556.     PyBufferObject *self;
  557.     int idx;
  558.     const char ** pp;
  559. {
  560.     if ( idx != 0 ) {
  561.         PyErr_SetString(PyExc_SystemError,
  562.                 "accessing non-existent buffer segment");
  563.         return -1;
  564.     }
  565.     *pp = (const char *)self->b_ptr;
  566.     return self->b_size;
  567. }
  568.  
  569.  
  570. static PySequenceMethods buffer_as_sequence = {
  571.     (inquiry)buffer_length, /*sq_length*/
  572.     (binaryfunc)buffer_concat, /*sq_concat*/
  573.     (intargfunc)buffer_repeat, /*sq_repeat*/
  574.     (intargfunc)buffer_item, /*sq_item*/
  575.     (intintargfunc)buffer_slice, /*sq_slice*/
  576.     (intobjargproc)buffer_ass_item, /*sq_ass_item*/
  577.     (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
  578. };
  579.  
  580. static PyBufferProcs buffer_as_buffer = {
  581.     (getreadbufferproc)buffer_getreadbuf,
  582.     (getwritebufferproc)buffer_getwritebuf,
  583.     (getsegcountproc)buffer_getsegcount,
  584.     (getcharbufferproc)buffer_getcharbuf,
  585. };
  586.  
  587. PyTypeObject PyBuffer_Type = {
  588.     PyObject_HEAD_INIT(&PyType_Type)
  589.     0,
  590.     "buffer",
  591.     sizeof(PyBufferObject),
  592.     0,
  593.     (destructor)buffer_dealloc, /*tp_dealloc*/
  594.     0,        /*tp_print*/
  595.     0,        /*tp_getattr*/
  596.     0,        /*tp_setattr*/
  597.     (cmpfunc)buffer_compare, /*tp_compare*/
  598.     (reprfunc)buffer_repr, /*tp_repr*/
  599.     0,        /*tp_as_number*/
  600.     &buffer_as_sequence,    /*tp_as_sequence*/
  601.     0,        /*tp_as_mapping*/
  602.     (hashfunc)buffer_hash,    /*tp_hash*/
  603.     0,        /*tp_call*/
  604.     (reprfunc)buffer_str,        /*tp_str*/
  605.     0,        /*tp_getattro*/
  606.     0,        /*tp_setattro*/
  607.     &buffer_as_buffer,    /*tp_as_buffer*/
  608.     Py_TPFLAGS_DEFAULT,    /*tp_flags*/
  609.     0,        /*tp_doc*/
  610. };
  611.  
  612.